import { defineStore } from "pinia";
import { useUrlStore } from "@/store";
import NotificationUtil from "@/utils/model/NotificationUtil";
import { OrderType } from "@/store/components/HomeStore";
import { ClusterNode, Field, IndexItem, Mapping } from "$/elasticsearch-client";
import { clientIndexGetApi, clientIndexListApi, clientInstanceClusterHealthApi } from "@/api";
import { LoadingPlugin } from "tdesign-vue-next";
import MessageUtil from "@/utils/model/MessageUtil";

function renderMap(indices: Array<IndexItem>): Map<string, IndexItem> {
  const indicesMap = new Map<string, IndexItem>();
  for (const index of indices) {
    const names = [index.name, ...index.alias];
    for (const name of names) {
      indicesMap.set(name, index);
    }
  }
  return indicesMap;
}

export interface IndexOption {
  // 标签
  label: string;
  // 值，是唯一的
  value: string;
  // 标签
  tag: "index" | "alias" | "custom";
  // 暂无作用
  item?: IndexItem | undefined;
}

const buildItem = (
  items: Set<IndexOption>,
  names: Set<string>,
  alias: Array<string>,
  name: string,
  showType: boolean,
  type: string,
  item?: IndexItem
) => {
  names.add(`${name}:${type}`);
  items.add({
    label: showType ? `${name} 「${type}」` : name,
    value: `${name}:${type}`,
    tag: "index",
    item
  });
  if (alias) {
    for (const al of alias) {
      const aliasName = showType ? `${al} 「${type}」` : al;
      // 别名可能重复
      const value = `${al}:${type}`;
      if (!names.has(value)) {
        names.add(value);
        items.add({
          label: aliasName,
          value: value,
          tag: "alias",
          item
        });
      }
    }
  }
};

/**
 * 索引信息
 */
export const useIndexStore = defineStore("index", {
  state: () => ({
    // 集群信息
    masterNode: "",
    nodes: {} as Record<string, ClusterNode>,
    // 全部的索引
    indices: new Array<IndexItem>(),
    indicesMap: new Map<string, IndexItem>(),
    // 服务器名称
    name: "",
    active_shards: 0,
    total_shards: 0,
    status: "",
    order: OrderType.NAME_ASC
  }),
  getters: {
    /**
     * 返回全部的链接
     */
    list: (state) => state.indices,
    /**
     * 索引映射
     */
    map: (state) => state.indicesMap,
    indexAliasMap: (state): Map<string, string> => {
      const aliasIndexMap = new Map<string, string>();
      state.indices.forEach((index) => {
        aliasIndexMap.set(index.name, index.name);
        [index.name, ...index.alias].forEach((alias) => aliasIndexMap.set(alias, index.name));
      });
      return aliasIndexMap;
    },
    /**
     * 渲染好的索引选项
     * @param state
     */
    indexOptions: (state): Array<IndexOption> => {
      const items = new Set<IndexOption>();
      const names = new Set<string>();
      const { indices } = state;
      if (indices.length === 0) {
        return Array.from(items);
      }
      for (const index of indices) {
        // 索引不会重名
        const { alias, name, types } = index;
        for (const type of types) {
          buildItem(items, names, alias, name, types.length > 1, type, index);
        }
      }
      // 此处是索引排序
      return Array.from(items).sort((e1, e2) => {
        return e1.value.localeCompare(e2.value, "zh");
      });
    },
    /**
     * 索引、别名 + 类型 => mapping
     */
    mappingMap: (state): Map<string, Mapping> => {
      const target = new Map<string, Mapping>();
      const { indices } = state;
      for (const index of indices) {
        const { name, alias, indexInfo, types } = index;
        for (const item of [name, ...alias]) {
          // 多类型
          for (const type of types) {
            target.set(`${item}:${type}`, indexInfo.mappings[type] as Mapping);
          }
        }
      }
      return target;
    },
    /**
     * 索引、别名 + 类型 => Array<Field>
     */
    fieldMap: (state): Map<string, Array<Field>> => {
      const target = new Map<string, Array<Field>>();
      const { indices } = state;
      for (const index of indices) {
        const { name, alias, fields, types } = index;
        for (const item of [name, ...alias]) {
          // 多类型
          for (const type of types) {
            target.set(`${item}:${type}`, fields);
          }
        }
      }
      return target;
    }
  },
  actions: {
    /**
     * 重新获取链接
     */
    async reset(): Promise<void> {
      const { id } = useUrlStore();
      if (!id) {
        return Promise.reject("链接不存在");
      }
      const old = useUrlStore().current;
      // 清空数据
      this.clear();
      // 初始化时加载
      const useLoading = LoadingPlugin({
        content: "开始构建索引信息"
      });
      try {
        // 获取索引信息
        const clusterInfo = await clientIndexListApi(id);
        this.indices = clusterInfo.indices;
        this.masterNode = clusterInfo.masterNode;
        this.nodes = clusterInfo.nodes;
        // 渲染map
        this.indicesMap = renderMap(this.indices);

        // 获取基本信息
        clientInstanceClusterHealthApi(id)
          .then((health) => {
            this.name = health.cluster_name;
            this.active_shards = health.active_shards;
            const unassigned_shards = health.unassigned_shards;
            this.total_shards = this.active_shards + unassigned_shards;
            this.status = health.status;
          })
          .catch((e) => NotificationUtil.error(e, "获取索引健康值失败"));

        this.sort(this.order);
        return Promise.resolve();
      } catch (e: any) {
        // 此处需要判断，错误的链接是不是当前链接
        if (useUrlStore().current === old) {
          useUrlStore().clear();
        }
        console.error(e);
        return Promise.reject(e);
      } finally {
        useLoading.hide();
      }
    },
    clear() {
      this.name = "";
      this.masterNode = "";
      this.nodes = {};
      this.indices = new Array<IndexItem>();
      this.indicesMap = new Map<string, IndexItem>();
      this.active_shards = 0;
      this.total_shards = 0;
      this.status = "";
    },
    field(indexName: string | IndexItem | undefined): Array<Field> {
      let indexView: IndexItem | undefined;
      if (typeof indexName === "string") {
        indexView = this.indicesMap.get(indexName);
      } else {
        indexView = indexName;
      }
      if (indexView) {
        return [
          {
            name: "_id",
            type: "text",
            dataIndex: "_id",
            label: "_id"
          },
          ...Array.from(indexView.fields)
        ];
      }
      return new Array<Field>();
    },
    sort(order: OrderType) {
      this.order = order;
      this.indices.sort((a, b) => {
        if (order === OrderType.NAME_ASC) {
          return a.name.localeCompare(b.name, "zh-CN");
        } else if (order === OrderType.NAME_DESC) {
          return b.name.localeCompare(a.name, "zh-CN");
        } else if (order === OrderType.SIZE_ASC) {
          return a.original_size - b.original_size;
        } else if (order === OrderType.SIZE_DESC) {
          return b.original_size - a.original_size;
        } else if (order === OrderType.DOCS_ASC) {
          return a.original_doc_count - b.original_doc_count;
        } else if (order === OrderType.DOCS_DESC) {
          return b.original_doc_count - a.original_doc_count;
        }
        return 0;
      });
    },
    async refreshIndex(index: IndexItem) {
      const { id } = useUrlStore();
      if (!id) return MessageUtil.error("链接不存在");
      // 刷新索引信息，就不要获取集群了，太大了
      for (let i = 0; i < this.indices.length; i++) {
        if (this.indices[i].name === index.name) {
          this.indices[i] = await clientIndexGetApi(id, index.name);
          return;
        }
      }
    }
  }
});
